#if defined(___OS_WIN)
#include <windows.h>
#include <winbase.h>
#endif
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/timeb.h>
#if defined(___OS_LIN)
#include <signal.h>
#include <pthread.h>
#include <dlfcn.h>
#include <sys/mman.h>
#include <sys/time.h>
#endif


/* External: ___GUI, ___DLLIMP */
/* Internal: ___EXE, ___LIB, ___THR */


#if defined(___SYS_I486)
#define ___SYS "i486"
#if !defined(___SYS_I386)
#define ___SYS_I386
#endif
#elif defined(___SYS_I386)
#define ___SYS "i386"
#else
#error Missing system
#endif
#if defined(___OS_WIN)
#define ___OS "win32"
#elif defined(___OS_LIN)
#define ___OS "linux"
#else
#error Missing OS
#endif
#if defined(___SYS_I386)
#if !defined(___LSB)
#define ___LSB
#endif
#endif
#if !defined(___LSB) && !defined(___MSB)
#error Missing byteorder
#endif
#if defined(___LSB) && defined(___MSB)
#error Invalid byteorder
#endif


typedef void xx;
typedef   signed char  I1;
typedef unsigned char  N1;
typedef   signed short int I2;
typedef unsigned short int N2;
typedef   signed long  int I4;
typedef unsigned long  int N4;
typedef xx *Ptr;
typedef N1 *Str;
typedef N4 (*fFun)(N4 par);


#include "lib/sys.h"


#define S                (Str)
#define CS               char *
#define Bit(n)           (1ul<<(n))
#define Typ(t,v)         ((t)(v))
#define mp1(p,n)         Typ(N1 *,Typ(N1 *,p)+(n))
#define mp2(p,n)         Typ(N2 *,Typ(N1 *,p)+(n))
#define mp4(p,n)         Typ(N4 *,Typ(N1 *,p)+(n))
#define mn1(p,n)         (*mp1(p,n))
#define mn2(p,n)         (*mp2(p,n))
#define mn4(p,n)         (*mp4(p,n))
#define mn1x(p,n)        mx1(mn1(p,n))
#define mn2x(p,n)        mx2(mn2(p,n))
#define mn4x(p,n)        mx4(mn4(p,n))
#if defined(___MSB)
#define mx1(d)           Typ(N1,d)
#define mx2(d)           Typ(N2,d)
#define mx4(d)           Typ(N4,d)
#else
#define mx1(d)              (Typ(N1,d))
#define mx2(d)           sw2(Typ(N2,d))
#define mx4(d)           sw4(Typ(N4,d))
#endif
#define msw2(d)          ((Typ(N2,d)<<8)|(Typ(N2,d)>>8))
#define msw4(d)          (((Typ(N4,d))>>24)| \
                          ((Typ(N4,d)&0x00FF0000ul)>>8)| \
                          ((Typ(N4,d)&0x0000FF00ul)<<8)| \
                          ((Typ(N4,d))<<24))
#define BEG              do {
#define END              } while (0)
#define ERR0(s)          BEG fprintf(err,s "\n"); \
                         fflush(stdout); fflush(err); \
                         return (-1); END
#define ERR1(s,n1)       BEG fprintf(err,s "\n",n1); \
                         fflush(stdout); fflush(err); \
                         return (-1); END
#define ERR2(s,n1,n2)    BEG fprintf(err,s "\n",n1,n2); \
                         fflush(stdout); fflush(err); \
                         return (-1); END
#define ERR3(s,n1,n2,n3) BEG fprintf(err,s "\n",n1,n2,n3); \
                         fflush(stdout); fflush(err); \
                         return (-1); END

#define fCC              0x0F
#define _fZR             0
#define _fSN             1
#define _fCY             2
#define _fOF             3
#define _fSGN            4
#define _fFLG            15
#define fZR              Bit(_fZR)
#define fSN              Bit(_fSN)
#define fCY              Bit(_fCY)
#define fOF              Bit(_fOF)
#define fSGN             Bit(_fSGN)
#define fFLG             Bit(_fFLG)
#define zzFLG            flg&=~fCC
#define mFLz(d)          BEG if (!(d)) flg|=fZR; END
#define mFLs(d)          BEG if (Typ(I4,d)<0) flg|=fSN; END
#define mFLc(d)          BEG if (Typ(I4,d)<0) flg|=fCY; END
#define mFLo(d)          BEG if (Typ(I4,d)<0) flg^=fOF; END
#define mFLso(d)         BEG if (Typ(I4,d)<0) { flg|=fSN; flg^=fOF; } END
#define mFLco(d1,d2)     BEG if (Typ(N4,d1)<Typ(N4,d2)) { flg|=fCY; flg^=fOF; } END
#define mFLzs(d)         BEG mFLz(d); mFLs(d); END
#define mFLzso(d)        BEG mFLz(d); mFLso(d); END

#define rFL              0x00u
#define rIP              0x04u
#define rSP              0x08u
#define rBP              0x0Cu
#define rD1              0x10u
#define rD2              0x14u
#define rCNT             0x18u
#define rTIM             0x1Cu
#define rMAX             0x20u
#define rLEN             0x24u
#define rBEG             0x28u
#define rBLK             0x2Cu
#define gREG(r)          mn4x(mem,r)
#define sREG(r,v)        mn4(mem,r)=mx4(v)
#define gREG1(r)         mn1(mem,r)
#define sREG1(r,v)       mn1(mem,r)=(v)
#define gFL              gREG(rFL)
#define gIP              mp1(mem,gREG(rIP))
#define gSP              mp4(mem,gREG(rSP))
#define gBP              mp4(mem,gREG(rBP))
#define sFL(flg)         sREG(rFL,flg)
#define sIP(pip)         sREG(rIP,Typ(N1 *,pip)-mem)
#define sSP(psp)         sREG(rSP,Typ(N1 *,psp)-mem)
#define sBP(pbp)         sREG(rBP,Typ(N1 *,pbp)-mem)
#define mDif(p1,p2)      Typ(N4,Typ(N1 *,p1)-Typ(N1 *,p2))
#define mMem1(p1,p2)     (Typ(N1 *,(p2))<Typ(N1 *,p1)+REGLEN)
#define mMem2(p1,p2,n)   (Typ(N1 *,(p2)+(n))>Typ(N1 *,p1)+ml)
#define mMem(p1,p2,n)    (mMem1(p1,p2) || mMem2(p1,p2,n))
#define mStk(n,s)        if (mMem(mem,psp,n)) \
                           ERR2("Error: %08lX: " s ": %08lX", \
                           mDif(pip,mem),mDif(psp,mem))

#define FileNamLen       255ul
#define FileOpenRead     Bit(0)
#define FileOpenWrite    Bit(1)
#define FileSeekBeg      0
#define FileSeekEnd      1
#define FileSeekCur      2


#define REGLEN 256ul
#define MEMLEN (256ul*1024ul)
#define LABNUM 1024ul
#define REFNUM 1024ul
typedef struct _tLab
{ N1 typ,c1,c2;
  N4 adr,x,y;
} tLab;
static tLab lab[LABNUM]={};
static tLab ref[REFNUM]={};
static FILE *err=NULL;
static FILE *inp=NULL;
static FILE *out=NULL;


static inline N2 sw2(N2 d)
{ return (msw2(d));
}
static inline N4 sw4(N4 d)
{ return (msw4(d));
}
static Ptr MemGet(N4 len)
{ if (!len) return (NULL);
  return (malloc(len));
}
static xx MemRel(Ptr p)
{ if (p) free(p);
}
static xx MemCpy(Str s1,Str s2,N4 l1)
{ if (!s1 || !s2) return;
  if (s1==s2) return;
  if (s1>=s2)
  { while (l1--) *s2++=*s1++;
  } else
  { s1+=l1-1; s2+=l1-1;
    while (l1--) *s2--=*s1--;
  }
}
static N4 StrLen(Str s1)
{ N4 i1;
  if (!s1) return (0);
  for (i1=0;*s1++;++i1);
  return (i1);
}
N4 dump(N1 *mem,FILE *f1);
N4 LabRef(xx);
N4 SetLab(N1 *mem,N4 i1);
N4 SetRef(N1 *mem,N4 i1);
N4 SetRef1(N1 *mem,N4 i1,N4 n1);
N1 *Num2Str(N1 sn,N1 bs,N4 num,N1 *s1,N1 l1);
N4 StrH2Num(N1 *buf);
N4 StrD2Num(N1 *buf);
N4 Str2Num(N1 *buf);
N4 deb(N1 *mem,N4 *tip);
// File
N4 FileCheck(Str nam,N4 *len,N4 *tms);
N4 FileCreate(Str nam);
N4 FileDelete(Str nam);
N4 FileOpen(N1 mod,Str nam);
xx FileClose(N4 id);
N4 FileRead(N4 id,Ptr buf,N4 len);
N4 FileWrite(N4 id,Ptr buf,N4 len);
N4 FileSeek(N1 mod,N4 id,I4 pos);
N4 FileResize(N4 id,N4 len);
N4 FileRename(Str nam1,Str nam2);


typedef enum _nSys
{ xStdGet=0, xStdPut, xStdErr, xHalt, xArgs, xPuts, xNum2Str,
  xStr2Num, xTimeGet, xTimeSet, xTimeWait, xTimeConv,
  xFileCheck, xFileCreate, xFileDelete, xFileOpen, xFileClose,
  xFileRead, xFileWrite, xFileSeek, xFileResize, xFileRename,
  xSysCmd, xDirList, xCwdGet, xCwdSet, xEnvGet, xEnvSet,
  xSysInf, xTypSys, xTypOS, xExec,
  xLibOpen, xLibClose, xAdrGet, xAdrRel, xMemExe,
  xThBeg, xThEnd, xThId, xLkGet, xLkRel, xLkBeg, xLkEnd,
  xEvtGet, xEvtRel, xEvtSet, xEvtNul, xEvtWait,
} nSys;
I4 sys(N1 **cmd,N1 *mem,N4 ml,N1 *pip,N4 **_psp)
{ N4 *psp=*_psp,n1,n2; N1 *p1,*p2,*p3;

  n1=mx4(psp[0]);
  switch (n1)
  { case xStdGet: // StdGet(xx):N4
      n1=(I4)fgetc(stdin);
      psp[0]=mx4(n1);
      break;
    case xStdPut: // StdPut(N1 cc):xx
      mStk(2,"SYS/StdPut/STK");
      n1=mx4(psp[1]);
      fputc((N1)n1,stdout);
      fflush(stdout);
      *_psp+=2; break;
    case xStdErr: // StdErr(N1 cc):xx
      mStk(2,"SYS/StdErr/STK");
      n1=mx4(psp[1]);
      fputc((N1)n1,err);
      fflush(err);
      *_psp+=2; break;
    case xHalt: // Halt
      ERR1("Error: %08lX: SYS/Halt",mDif(pip,mem));
    case xArgs: // Args(N4 num,Str s1,N4 l1):N4
      mStk(4,"SYS/Args/STK");
      n1=mx4(psp[2]); n2=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,n2))
        ERR1("Error: %08lX: SYS/Args: Str",mDif(pip,mem));
      if (cmd)
      { for (n2=mx4(psp[3]),n1=0;n1<n2 && *cmd;++n1,++cmd);
        n2=mx4(psp[1]); if (!*cmd) n1=0;
        else { for (p2=*cmd,n1=0;*p2++;++n1); ++n1; }
        if (n1<n2) for (p2=*cmd;p2 && n1--;) *p1++=*p2++;
      } else n1=0;
      *p1=0; psp[3]=mx4(n1);
      *_psp+=3; break;
    case xPuts: // Puts(Str s1):xx
      mStk(2,"SYS/Puts/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/Puts: Str",mDif(pip,mem));
      fputs(p1,stdout); fflush(stdout);
      *_psp+=2; break;
    case xNum2Str: // Num2Str(N1 sn,N1 bs,N4 num,Str s1):Str
      mStk(5,"SYS/Num2Str/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,10))
        ERR1("Error: %08lX: SYS/Num2Str: Str",mDif(pip,mem));
      if (!(p1=Num2Str(mx4(psp[4]),mx4(psp[3]),mx4(psp[2]),p1,0)))
        ERR1("Error: %08lX: Sys/Num2Str: Conv",mDif(pip,mem));
      n1=mDif(p1,mem); psp[4]=mx4(n1);
      *_psp+=4; break;
    case xStr2Num: // Str2Num(Str s1):N4
      mStk(2,"SYS/Str2Num/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/Str2Num: Par2",mDif(pip,mem));
      n1=Str2Num(p1); psp[1]=mx4(n1);
      *_psp+=1; break;

    case xTimeGet: // TimeGet(N4 *msec):N4
      mStk(2,"SYS/TimeGet/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,4))
        ERR1("Error: %08lX: SYS/TimeGet: Par1",mDif(pip,mem));
      n1=TimeGet((N4 *)p1); psp[1]=mx4(n1);
      *_psp+=1; break;
    case xTimeSet: // TimeSet(N4 tms,N4 msec):N4
      mStk(3,"SYS/TimeSet/STK");
      n1=TimeSet(mx4(psp[2]),mx4(psp[1])); psp[2]=mx4(n1);
      *_psp+=2; break;
    case xTimeWait: // TimeWait(N4 tmm):xx
      mStk(2,"SYS/TimeWait/STK");
      TimeWait(mx4(psp[1]));
      *_psp+=2; break;
    case xTimeConv: // TimeConv(N1 bk,Ptr dt,N4 *tms):N4
      mStk(4,"SYS/TimeConv/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/TimeConv: Par2",mDif(pip,mem));
      n1=mx4(psp[1]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,4))
        ERR1("Error: %08lX: SYS/TimeConv: Par3",mDif(pip,mem));
      n1=TimeConv(mx4(psp[3]),(tTime *)p1,(N4 *)p2); psp[3]=mx4(n1);
      *_psp+=3; break;

    case xFileCheck: // FileCheck(Str nam,N4 *len,N4 *tms):N4
      mStk(4,"SYS/FileCheck/STK");
      n1=mx4(psp[3]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileCheck: Par1",mDif(pip,mem));
      n1=mx4(psp[2]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,4))
        ERR1("Error: %08lX: SYS/FileCheck: Par2",mDif(pip,mem));
      n1=mx4(psp[1]); p3=mp1(mem,n1);
      if (!n1 || mMem(mem,p3,4))
        ERR1("Error: %08lX: SYS/FileCheck: Par3",mDif(pip,mem));
      n1=FileCheck(p1,(N4 *)p2,(N4 *)p3); psp[3]=mx4(n1);
      *_psp+=3; break;
    case xFileCreate: // FileCreate(Str nam):N4
      mStk(2,"SYS/FileCreate/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileCreate: Nam",mDif(pip,mem));
      n1=FileCreate(p1); psp[1]=mx4(n1);
      *_psp+=1; break;
    case xFileDelete: // FileDelete(Str nam):N4
      mStk(2,"SYS/FileDelete/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileDelete: Nam",mDif(pip,mem));
      n1=FileDelete(p1); psp[1]=mx4(n1);
      *_psp+=1; break;
    case xFileOpen: // FileOpen(N1 mod,Str nam):N4
      mStk(3,"SYS/FileOpen/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileOpen: Nam",mDif(pip,mem));
      n1=FileOpen(mx4(psp[2]),p1); psp[2]=mx4(n1);
      *_psp+=2; break;
    case xFileClose: // FileClose(N4 id):xx
      mStk(2,"SYS/FileClose/STK");
      FileClose(mx4(psp[1]));
      *_psp+=2; break;
    case xFileRead: // FileRead(N4 id,Ptr buf,N4 len):N4
      mStk(4,"SYS/FileRead/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileRead: Buf",mDif(pip,mem));
      n1=FileRead(mx4(psp[3]),p1,mx4(psp[1])); psp[3]=mx4(n1);
      *_psp+=3; break;
    case xFileWrite: // FileWrite(N4 id,Ptr buf,N4 len):N4
      mStk(4,"SYS/FileWrite/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileWrite: Buf",mDif(pip,mem));
      n1=FileWrite(mx4(psp[3]),p1,mx4(psp[1])); psp[3]=mx4(n1);
      *_psp+=3; break;
    case xFileSeek: // FileSeek(N1 mod,N4 id,I4 pos):N4
      mStk(4,"SYS/FileSeek/STK");
      n1=FileSeek(mx4(psp[3]),mx4(psp[2]),mx4(psp[1]));
      psp[3]=mx4(n1);
      *_psp+=3; break;
    case xFileResize: // FileResize(N4 id,N4 len):N4
      mStk(3,"SYS/FileResize/STK");
      n1=FileResize(mx4(psp[2]),mx4(psp[1]));
      psp[2]=mx4(n1);
      *_psp+=2; break;
    case xFileRename: // FileRename(Str nam1,Str nam2):N4
      mStk(3,"SYS/FileRename/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/FileRename: Par1",mDif(pip,mem));
      n1=mx4(psp[1]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,1))
        ERR1("Error: %08lX: SYS/FileRename: Par2",mDif(pip,mem));
      n1=FileRename(p1,p2); psp[2]=mx4(n1);
      *_psp+=2; break;

    case xSysCmd: // SysCmd(Str cmd):N4
      mStk(2,"SYS/SysCmd/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/SysCmd: Par1",mDif(pip,mem));
      n1=SysCmd(p1); psp[1]=mx4(n1);
      *_psp+=1; break;
    case xDirList: // DirList(Str nam,Str buf,N4 len):N4
      mStk(4,"SYS/DirList/STK");
      n1=mx4(psp[3]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/DirList: Par1",mDif(pip,mem));
      n1=mx4(psp[2]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,1))
        ERR1("Error: %08lX: SYS/DirList: Par2",mDif(pip,mem));
      n1=DirList(p1,p2,mx4(psp[1])); psp[3]=mx4(n1);
      *_psp+=3; break;
    case xCwdGet: // CwdGet(Str nam,N4 nlen):N4
      mStk(3,"SYS/CwdGet/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/CwdGet: Par1",mDif(pip,mem));
      n1=CwdGet(p1,mx4(psp[1])); psp[2]=mx4(n1);
      *_psp+=2; break;
    case xCwdSet: // CwdSet(Str nam):N4
      mStk(2,"SYS/CwdSet/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/CwdSet: Par1",mDif(pip,mem));
      n1=CwdSet(p1); psp[1]=mx4(n1);
      *_psp+=1; break;
    case xEnvGet: // EnvGet(Str s1,Str s2,N4 l2):N4
      mStk(4,"SYS/EnvGet/STK");
      n1=mx4(psp[3]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/EnvGet: Par1",mDif(pip,mem));
      n1=mx4(psp[2]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,1))
        ERR1("Error: %08lX: SYS/EnvGet: Par2",mDif(pip,mem));
      n1=EnvGet(p1,p2,mx4(psp[1])); psp[3]=mx4(n1);
      *_psp+=3; break;
    case xEnvSet: // EnvSet(Str s1,Str s2):N4
      mStk(3,"SYS/EnvSet/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/EnvSet: Par1",mDif(pip,mem));
      n1=mx4(psp[1]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,1))
        ERR1("Error: %08lX: SYS/EnvSet: Par2",mDif(pip,mem));
      n1=EnvSet(p1,p2); psp[2]=mx4(n1);
      *_psp+=2; break;
    case xSysInf: // SysInf(N4 num):N4
      mStk(2,"SYS/SysInf/STK");
      switch (mx4(psp[1]))
      { case 0: n1=isth; break;
        case 1: n1=ml; break;
        case 2: n1=(N4)mem; break;
        case 3: n1=(N4)sys; break;
        case 4: n1=(N4)prog; break; /* vm1 */
        case 5: n1=(N4)MemGet; break;
        case 6: n1=(N4)MemRel; break;
        default: n1=-1; break;
      }
      psp[1]=mx4(n1);
      *_psp+=1; break;
    case xTypSys: // TypSys(Str buf,N4 len):N4
      mStk(2,"SYS/TypSys/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/TypSys: Par1",mDif(pip,mem));
      n1=mx4(psp[1]); n2=StrLen(p2=TypSys)+1;
      if (n1<n2) n1=-n2; else
      { MemCpy(p2,p1,n2); n1=0; }
      psp[2]=mx4(n1);
      *_psp+=2; break;
    case xTypOS: // TypOS(Str buf,N4 len):N4
      mStk(2,"SYS/TypOS/STK");
      n1=mx4(psp[2]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/TypOS: Par1",mDif(pip,mem));
      n1=mx4(psp[1]); n2=StrLen(p2=TypOS)+1;
      if (n1<n2) n1=-n2; else
      { MemCpy(p2,p1,n2); n1=0; }
      psp[2]=mx4(n1);
      *_psp+=2; break;
    case xExec: // Exec(Ptr fun,N4 par):N4
      mStk(3,"SYS/Exec/STK");
      n1=mx4(psp[2]); if (!n1)
        ERR1("Error: %08lX: SYS/Exec: Par1",mDif(pip,mem));
      n1=Typ(fFun,n1)(mx4(psp[1])); psp[2]=mx4(n1);
      *_psp+=2; break;


    case xLibOpen: // LibOpen(Str nam):N4
      mStk(2,"SYS/LibOpen/STK");
      n1=mx4(psp[1]); p1=mp1(mem,n1);
      if (!n1 || mMem(mem,p1,1))
        ERR1("Error: %08lX: SYS/LibOpen: Par1",mDif(pip,mem));
      n1=LibOpen(p1); psp[1]=mx4(n1);
      *_psp+=1; break;
    case xLibClose: // LibClose(N4 id):xx
      mStk(2,"SYS/LibClose/STK");
      LibClose(mx4(psp[1]));
      *_psp+=2; break;
    case xAdrGet: // AdrGet(N4 id,Str nam):Ptr
      mStk(3,"SYS/AdrGet/STK");
      n1=mx4(psp[1]); p2=mp1(mem,n1);
      if (!n1 || mMem(mem,p2,1))
        ERR1("Error: %08lX: SYS/AdrGet: Par2",mDif(pip,mem));
      n1=(N4)AdrGet(mx4(psp[2]),p2); psp[2]=mx4(n1);
      *_psp+=2; break;
    case xAdrRel: // AdrRel(N4 id,Ptr adr):xx
      mStk(3,"SYS/AdrRel/STK");
      n1=mx4(psp[1]); if (!n1)
        ERR1("Error: %08lX: SYS/AdrRel: Par2",mDif(pip,mem));
      AdrRel(mx4(psp[2]),(Ptr)n1);
      *_psp+=3; break;
    case xMemExe: // MemExe(Ptr mem,N4 len):N4
      mStk(3,"SYS/MemExe/STK");
      n1=mx4(psp[2]); if (!n1)
        ERR1("Error: %08lX: SYS/MemExe: Par1",mDif(pip,mem));
      n1=MemExe((Ptr)n1,mx4(psp[1])); psp[2]=mx4(n1);
      *_psp+=2; break;

    case xThBeg: // ThBeg(Ptr fun,N4 par):N4
      mStk(3,"SYS/ThBeg/STK");
      n1=mx4(psp[2]); if (!n1)
        ERR1("Error: %08lX: SYS/ThBeg: Par1",mDif(pip,mem));
      n1=ThBeg((fFun)n1,mx4(psp[1])); psp[2]=mx4(n1);
      *_psp+=2; break;
    case xThEnd: // ThEnd(N4 id):xx
      mStk(2,"SYS/ThEnd/STK");
      ThEnd(mx4(psp[1]));
      *_psp+=2; break;
    case xThId: // ThId(xx):N4
      n1=ThId();
      psp[0]=mx4(n1);
      break;
    case xLkGet: // ThLkGet(xx):N4
      n1=ThLkGet();
      psp[0]=mx4(n1);
      break;
    case xLkRel: // ThLkRel(N4 id):xx
      mStk(2,"SYS/ThLkRel/STK");
      ThLkRel(mx4(psp[1]));
      *_psp+=2; break;
    case xLkBeg: // ThLkBeg(N4 id):N4
      mStk(2,"SYS/ThLkBeg/STK");
      n1=ThLkBeg(mx4(psp[1]));
      psp[1]=mx4(n1);
      *_psp+=1; break;
    case xLkEnd: // ThLkEnd(N4 id):N4
      mStk(2,"SYS/ThLkEnd/STK");
      n1=ThLkEnd(mx4(psp[1]));
      psp[1]=mx4(n1);
      *_psp+=1; break;
    case xEvtGet: // ThEvtGet(xx):N4
      n1=ThEvtGet();
      psp[0]=mx4(n1);
      break;
    case xEvtRel: // ThEvtRel(N4 id):xx
      mStk(2,"SYS/ThEvtRel/STK");
      ThEvtRel(mx4(psp[1]));
      *_psp+=2; break;
    case xEvtSet: // ThEvtSet(N4 id):N4
      mStk(2,"SYS/ThEvtSet/STK");
      n1=ThEvtSet(mx4(psp[1]));
      psp[1]=mx4(n1);
      *_psp+=1; break;
    case xEvtNul: // ThEvtNul(N4 id):N4
      mStk(2,"SYS/ThEvtNul/STK");
      n1=ThEvtNul(mx4(psp[1]));
      psp[1]=mx4(n1);
      *_psp+=1; break;
    case xEvtWait: // ThEvtWait(N4 id,N4 lk,N4 tmm):xx
      mStk(4,"SYS/ThEvtWait/STK");
      ThEvtWait(mx4(psp[3]),mx4(psp[2]),mx4(psp[1]));
      *_psp+=4; break;

    default:
      ERR2("Error: %08lX: SYS/%08lX",mDif(pip,mem),n1);
  }
  return (0);
}

N4 prog(N4 pnum,Str *par)
{ N4 tip=0,n1,n2,n3; I4 i1,i2;
  N1 run=1,idb=0; N4 flg,cnt;
  N1 *mem,*pip; N4 *psp,*pbp;
  N1 **cmd=NULL; N4 ml=MEMLEN;
  FILE *exe=NULL;

  err=stderr; inp=stdin;
  SysInit();

  // Args
  for (n1=0;n1<pnum;++n1)
  { N1 *s1=*(par++);
    if (*s1!='-')
      ERR1("Error: Arg: '%s'",s1);
    switch (s1[1])
    { case 'h':
        puts("Args: [-hrd] [-m[k|m]<len>] [-i<file> | -x<file>] [-c<file>] [-- <cmd>]");
        return (0);
      case 'r':
        err=stdout;
        break;
      case 'd':
        idb=1;
        break;
      case 'm':
        i1=2; i2=1;
        switch (s1[i1])
        { case 'k': ++i1; i2=1ul<<10; break;
          case 'm': ++i1; i2=1ul<<20; break;
        }
        for (n2=0;s1[i1];++i1)
          n2=(n2*10)+s1[i1]-'0';
        ml=n2*i2;
        break;
      case 'i':
        if (!(inp=fopen(s1+2,"rb")))
          ERR0("Error: Open: Input");
        break;
      case 'x':
        if (!(exe=fopen(s1+2,"rb")))
          ERR0("Error: Open: Exec");
        break;
      case 'c':
        if (!(out=fopen(s1+2,"wb")))
          ERR0("Error: Open: Output");
        break;
      case '-':
        cmd=(N1 **)par;
        break;
    }
    if (cmd) break;
  }
  if (idb && inp==stdin && !exe)
    ERR0("Error: Debug: Noinp");
  if (!(mem=MemGet(ml)))
    ERR0("Error: Mem: Len");
  for (pip=mem,n1=0;n1<ml;++n1)
    *pip++=0;
  if (exe)
  { if (inp!=stdin) fclose(inp);
    for (n1=REGLEN;n1<ml;++n1)
    { int ii; N1 cc;
      ii=fgetc(exe);
      if (ii==-1) break;
      else cc=(N1)ii;
      mem[n1]=cc;
    }
    fclose(exe); inp=exe;
    if (n1==ml)
      ERR0("Error: Nomem: File");
    sREG(rLEN,n1-REGLEN);
  }

  // Init
  flg=0; cnt=-1;
  pip=mp1(mem,REGLEN);
  psp=mp4(mem,ml);
  pbp=mp4(mem,ml);
  sFL(flg); sREG(rCNT,cnt);
  sIP(pip); sSP(psp); sBP(pbp);
  sREG(rMAX,ml); sREG(rBEG,REGLEN);

  // Read
  { N1 bk=0,esc=0,str=0,cmt=0;
    N1 dig=0,num=0,*p1; N4 x=0,y=1;
    I4 blk=0; N1 ilb=0;
    int ii; N1 cc;
  for (n1=REGLEN;n1<ml;)
  { ii=fgetc(inp);
    if (ii==-1) break;
    else cc=(N1)ii;
    if (cc!='\n') ++x;
    else { ++y; x=0; }
    // Filter
    if (ilb)
    { if (esc)
      { esc=0; num=cc;
      } else
      { ilb=0; p1=mem+n1;
        if (dig || str)
        { for (i1=0;i1<REFNUM && ref[i1].adr;++i1);
          if (i1==REFNUM)
            ERR2("Error: (%lu,%lu): REF: More",y,x);
          ref[i1].typ=0; ref[i1].adr=n1;
          ref[i1].c1=num; ref[i1].c2=cc;
          ref[i1].x=x; ref[i1].y=y;
          ref[i1].typ=(dig?1:2);
          i2=((ref[i1].typ==1)?8:4);
          if (mMem(mem,p1,i2))
            ERR2("Error: (%lu,%lu): REF: Mem",y,x);
          for (n2=0;n2<i2;++n2) *p1++='_'; n1+=i2;
          if (SetRef(mem,i1)) return (-1);
          dig=0; str=0;
        } else
        { for (i1=0;i1<LABNUM && lab[i1].adr;++i1)
            if (lab[i1].c1==num && lab[i1].c2==cc) break;
          if (i1==LABNUM)
            ERR2("Error: (%lu,%lu): LAB: More",y,x);
          if (lab[i1].adr)
            ERR2("Error: (%lu,%lu): LAB: Redef",y,x);
          lab[i1].typ=0; lab[i1].adr=n1;
          lab[i1].c1=num; lab[i1].c2=cc;
          lab[i1].x=x; lab[i1].y=y;
          if (SetLab(mem,i1)) return (-1);
        }
      }
      continue;
    } else
    if (dig)
    { if ('0'<=cc && cc<='9') cc-='0'; else
      if ('A'<=cc && cc<='F') cc-='A'-10; else
      if (dig==1) ERR2("Error: (%lu,%lu): Num",y,x);
      else if (!(dig&1)) ERR2("Error: (%lu,%lu): Dig",y,x);
      else { dig=0; num=0; }
      if (dig)
      { if (dig&1)
        { num=cc; ++dig; }
        else
        { num=(num<<4)|cc; dig=3;
          mem[n1++]=num;
        }
        continue;
      }
    } else
    if (str)
    { if (esc)
      { esc=0; switch (cc)
        { case 'n':
            cc='\n'; break;
          case 'r':
            cc='\r'; break;
          case 't':
            cc='\t'; break;
        }
      } else
      { if (cc=='"')
        { str=0; continue; }
        if (cc=='\\')
        { esc=1; continue; }
      }
      mem[n1++]=cc;
      continue;
    } else
    if (cmt==1)
    { if (bk=='*' && cc=='/')
      { cmt=0; bk=0; continue; }
      bk=cc; continue;
    } else
    if (cmt==2)
    { if (cc=='\n') cmt=0;
      continue;
    }

    if (cc=='\\')
    { dig=1; bk=0; continue; }
    if (cc=='"')
    { str=1; bk=0; continue; }
    if (bk=='/')
    { if (cc=='*')
      { cmt=1; --n1; bk=0; continue; }
      if (cc=='/')
      { cmt=2; --n1; bk=0; continue; }
    }
    switch (cc)
    { case '\n':
      case '\r':
      case '\t':
      case ' ':
        bk=0; continue;
      case '{':
        if (++blk<0)
          ERR2("Error: (%lu,%lu): BLK1: Over",y,x);
        if (n1+6>ml)
          ERR2("Error: (%lu,%lu): BLK1: Mem",y,x);
        --psp; mStk(1,"BLK1/STK");
        *psp=mx4(n1);
        mem[n1++]='['; mem[n1++]='.';
        mem[n1++]='_'; mem[n1++]='_';
        mem[n1++]='_'; mem[n1++]='_';
        bk=0; continue;
      case '}':
        if (--blk<0)
          ERR2("Error: (%lu,%lu): BLK2: Under",y,x);
        mStk(1,"BLK2/STK");
        n2=mx4(*psp); ++psp; n3=n1-n2;
        if (n3>=0x10000ul)
          ERR2("Error: (%lu,%lu): BLK2: Len",y,x);
        { N1 *p1=mp1(mem,n2)+2;
        for (i2=12,i1=0;i1<4;++i1)
        { num=(n3>>i2)&0xF;
          if (num<10) num+='0';
          else num+='A'-10;
          *p1++=num; i2-=4;
        } }
        cc=']'; break;
      case ':':
        ilb=1; esc=1;
        bk=0; continue;
      case '=':
        ilb=1; esc=1; dig=1;
        bk=0; continue;
      case '@':
        ilb=1; esc=1; str=1;
        bk=0; continue;
    }
    mem[n1++]=bk=cc;
  } }
  if (inp!=exe)
  { if (n1==ml)
      ERR0("Error: Nomem: File");
    sREG(rLEN,n1-REGLEN);
    if (LabRef()) return (-1);
  }

  if (!out) while (run)
  { if (!idb) n1=0; else
    do n1=deb(mem,&tip);
    while (n1==1);
    if (n1==-1) break;
    flg=gFL; pip=gIP; psp=gSP; pbp=gBP;
    if (mMem(mem,pip,1))
      ERR1("Error: %08lX: IP",mDif(pip,mem));
    switch (*pip)
    { case '[':
        i1=gREG(rBLK)+1; sREG(rBLK,i1);
        if (i1<0)
          ERR1("Error: %08lX: BLK1: Over",mDif(pip,mem));
        --psp; mStk(1,"BLK1/STK");
        *psp=mx4(mDif(pip,mem));
        break;
      case ']':
        i1=gREG(rBLK)-1; sREG(rBLK,i1);
        if (i1<0)
          ERR1("Error: %08lX: BLK2: Under",mDif(pip,mem));
        mStk(2,"BLK2/STK"); psp+=2;
        break;
      case 'o':
        mStk(3,"CONT/STK");
        if (psp[0])
        { n1=gREG(rBLK);
          if (!n1--)
            ERR1("Error: %08lX: CONT",mDif(pip,mem));
          sREG(rBLK,n1);
          n1=mx4(psp[2]); psp+=3;
          pip=mp1(mem,n1)-1;
        } else psp+=1;
        break;
      case 'b':
        mStk(3,"BREAK/STK");
        if (psp[0])
        { n1=gREG(rBLK);
          if (!n1)
            ERR1("Error: %08lX: BREAK",mDif(pip,mem));
          n1=mx4(psp[2]); n1+=mx4(psp[1]);
          pip=mp1(mem,n1)-1;
        } else psp+=1;
        break;
      case '\n':
      case '\r':
      case '\t':
      case ' ':
      case ';': // NOP
        break;
      case '$': // SYS
        mStk(1,"SYS/STK");
        if (mx4(*psp)==3)
        { run=0; break; }
        if (sys(cmd,mem,ml,pip,&psp)) return (-1);
        break;
      case 'j': // JMP
        mStk(2,"JMP/STK");
        if (psp[1])
        { n1=mx4(*psp); n2=mDif(pip,mem);
          if (flg&fSGN) pip+=n1;
          else pip=mp1(mem,n1);
          if (mMem(mem,pip,1))
            ERR2("Error: %08lX: JMP: %08lX",
            n2,mDif(pip,mem));
          --pip;
        }
        psp+=2;
        break;
      case 'c': // CALL
        mStk(1,"CALL/STK");
        n1=mx4(*psp);
        n2=mDif(pip,mem);
        *psp=mx4(mDif(pip+1,mem));
        if (flg&fSGN) pip+=n1;
        else pip=mp1(mem,n1);
        if (mMem(mem,pip,1))
          ERR2("Error: %08lX: CALL: %08lX",
          n2,mDif(pip,mem));
        --pip;
        break;
      case '~': // SGN
        flg|=fFLG|fSGN;
        break;
      case 'G': // GET
        mStk(1,"GET/STK");
        n1=mx4(*psp);
        if (n1+4>ml)
          ERR2("Error: %08lX: GET: %08lX",
          mDif(pip,mem),n1);
        *psp=mn4(mem,n1);
        n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case 'g': // GT1
        mStk(1,"GT1/STK");
        n1=mx4(*psp);
        if (n1+1>ml)
          ERR2("Error: %08lX: GT1: %08lX",
          mDif(pip,mem),n1);
        n1=mn1(mem,n1);
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case 'S': // SET
        mStk(2,"SET/STK");
        n2=mx4(*psp++); n1=*psp++; sSP(psp);
        if (n2+4>ml)
          ERR2("Error: %08lX: SET: %08lX",
          mDif(pip,mem),n2);
        mn4(mem,n2)=(N4)n1;
        flg=gFL; pip=gIP; psp=gSP; pbp=gBP;
        if (n2==rIP) --pip;
        break;
      case 's': // ST1
        mStk(2,"ST1/STK");
        n2=mx4(*psp++); n1=mx4(*psp++); sSP(psp);
        if (n2+1>ml)
          ERR2("Error: %08lX: ST1: %08lX",
          mDif(pip,mem),n2);
        mn1(mem,n2)=(N1)n1;
        flg=gFL; pip=gIP; psp=gSP; pbp=gBP;
        if (n2==rIP) --pip;
        break;
      case 'w': // GT2
        mStk(1,"GT2/STK");
        n1=mx4(*psp);
        if (flg&fSGN)
          n1+=mDif(pip,mem);
        if (n1+2>ml)
          ERR2("Error: %08lX: GT2: %08lX",
          mDif(pip,mem),n1);
        n1=mn2(mem,n1); n1=mx2(n1);
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case 'W': // ST2
        mStk(2,"ST2/STK");
        n2=mx4(*psp++); n1=mx4(*psp++); sSP(psp);
        if (flg&fSGN)
          n2+=mDif(pip,mem);
        if (n2+2>ml)
          ERR2("Error: %08lX: ST2: %08lX",
          mDif(pip,mem),n2);
        mn2(mem,n2)=mx2(n1);
        flg=gFL; pip=gIP; psp=gSP; pbp=gBP;
        if (n2==rIP) --pip;
        break;
      case 'p': // POP
        mStk(1,"POP/STK");
        ++psp; break;
      case 'm': // DUP
        --psp;
        mStk(2,"DUP/STK");
        psp[0]=psp[1];
        n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case 'x': // XCH
        mStk(2,"XCH/STK");
        n1=psp[0];
        psp[0]=psp[1];
        psp[1]=n1;
        break;
      case 'i': // INT1
        mStk(1,"INT1/STK");
        n1=mx4(*psp);
        n1=(I4)(I1)n1;
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case 'I': // INT2
        mStk(1,"INT2/STK");
        n1=mx4(*psp);
        n1=(I4)(I2)n1;
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case '.': // ZRO
        --psp;
        mStk(1,"ZRO/STK");
        n1=*psp=0;
        zzFLG; mFLzs(n1);
        break;
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case 'A':
      case 'B':
      case 'C':
      case 'D':
      case 'E':
      case 'F': // NUM
        mStk(1,"NUM/STK");
        n1=mx4(*psp); n2=*pip;
        if ('0'<=n2 && n2<='9')
          n2-='0'; else n2-='A'-10;
        n1=(n1<<4)|n2; *psp=mx4(n1);
        break;
      case '+': // ADD
        mStk(2,"ADD/STK");
        n2=mx4(*psp++); n1=mx4(*psp);
        zzFLG; mFLo(n1^n2);
        *psp=mx4(n2=n1+n2);
        mFLzso(n2); mFLco(n2,n1);
        break;
      case '-': // SUB
        mStk(2,"SUB/STK");
        n2=mx4(*psp++); n1=mx4(*psp);
        zzFLG; mFLo(n1^n2);
        *psp=mx4(n2=n1-n2);
        mFLzso(n2); mFLco(n1,n2);
        break;
      case '*': // MUL
        mStk(2,"MUL/STK");
        n2=mx4(*psp++); n1=mx4(*psp);
        if (flg&fSGN)
          *psp=mx4(n1=Typ(I4,n1)*Typ(I4,n2));
        else
          *psp=mx4(n1=Typ(N4,n1)*Typ(N4,n2));
        zzFLG; mFLzs(n1);
        break;
      case '/': // DIV
        mStk(2,"DIV/STK");
        n2=mx4(psp[0]); n1=mx4(psp[1]); if (!n1)
          ERR1("Error: %08lX: Div 0",mDif(pip,mem));
        if (flg&fSGN)
        { psp[1]=mx4(Typ(I4,n1)/Typ(I4,n2));
          psp[0]=mx4(Typ(I4,n1)%Typ(I4,n2));
        } else
        { psp[1]=mx4(Typ(N4,n1)/Typ(N4,n2));
          psp[0]=mx4(Typ(N4,n1)%Typ(N4,n2));
        }
        n1=mx4(psp[1]);
        zzFLG; mFLzs(n1);
        break;
      case 'n': // NEG
        mStk(1,"NEG/STK");
        n1=-mx4(*psp);
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case '!': // NOT
        mStk(1,"NOT/STK");
        *psp=~*psp;
        n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case '&': // AND
        mStk(2,"AND/STK");
        n2=*psp++; *psp&=n2;
        n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case '|': // OR
        mStk(2,"OR/STK");
        n2=*psp++; *psp|=n2;
        n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case '^': // XOR
        mStk(2,"XOR/STK");
        n2=*psp++; *psp^=n2;
        n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case '<': // ROL
        mStk(2,"ROL/STK");
        n2=mx4(*psp++); n1=mx4(*psp);
        if (n2>32) n2=32;
        if (flg&fSGN)
        { n1=(n1<<n2)|(n1>>(32-n2));
          zzFLG; mFLzs(n1);
        } else
        { zzFLG; mFLo(n1);
          if (n2) mFLc(n1<<(n2-1));
          n1=n1<<n2; mFLzso(n1);
        }
        *psp=mx4(n1);
        break;
      case '>': // SAR
        mStk(2,"SAR/STK");
        n2=mx4(*psp++); n1=mx4(*psp);
        if (n2>32) n2=32;
        zzFLG; mFLo(n1);
        if (n2) mFLc(n1<<(32-n2));
        if (flg&fSGN)
          n1=Typ(I4,n1)>>n2;
        else
          n1=Typ(N4,n1)>>n2;
        mFLzso(n1);
        *psp=mx4(n1);
        break;
      case 'a': // ADR
        mStk(1,"ADR/STK");
        n1=mx4(*psp);
        n1=mDif(pbp+n1,mem);
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case 'v': // VAR
        mStk(1,"VAR/STK");
        n1=mx4(*psp);
        if (mMem(mem,pbp,n1))
          ERR2("Error: %08lX: VAR: %08lX",
          mDif(pip,mem),mDif(pbp+n1,mem));
        *psp=pbp[n1]; n1=mx4(*psp);
        zzFLG; mFLzs(n1);
        break;
      case 'z': // IZR
        mStk(1,"IZR/STK");
        if (flg&fSGN)
          n1=(*psp!=0);
        else
          n1=(*psp==0);
        *psp=mx4(n1);
        zzFLG; mFLzs(n1);
        break;
      case 'e': // EQU
        --psp;
        mStk(1,"EQU/STK");
        if (flg&fSGN)
          n1=((flg&fZR)?0:1);
        else
          n1=(flg>>_fZR)&1;
        *psp=mx4(n1);
        break;
      case 'l': // LESS
        --psp;
        mStk(1,"LESS/STK");
        if (flg&fSGN)
          n1=((flg>>_fSN)^(flg>>_fOF))&1;
        else
          n1=((flg&fCY)?1:0);
        *psp=mx4(n1);
        break;
      default:
        ERR2("Error: %08lX: Code: %02lX",mDif(pip,mem),(N4)*pip);
    }
    if (run)
    { ++pip;
      if (flg&fFLG) flg&=~fFLG;
      else flg&=~fSGN;
      cnt=gREG(rCNT)-1; sREG(rCNT,cnt);
    }
    sFL(flg); sIP(pip); sSP(psp); sBP(pbp);
  }
  if (out) dump(mem,out);
  MemRel(mem);
  fflush(stdout);
  return (0);
}

//====================================================================

N4 dump(N1 *mem,FILE *f1)
{ N4 n1; N1 *p1;

  if (!f1) return (0);
  p1=mp1(mem,REGLEN);
  n1=gREG(rLEN);
  if (fwrite(p1,n1,1,f1)!=1)
    ERR0("Error: Dump: Write");
  fclose(f1); return (0);
}

N4 LabRef(xx)
{ N4 i1;
  for (i1=0;i1<REFNUM && ref[i1].typ;++i1)
    if (ref[i1].adr)
      ERR2("Error: (%lu,%lu): Ref: Undef",
      ref[i1].y,ref[i1].x);
  return (0);
}

N4 SetLab(N1 *mem,N4 i1)
{ N4 i2,n1;
  for (i2=0;i2<REFNUM && ref[i2].typ;++i2)
  { if (!ref[i2].adr) continue;
    if (ref[i2].c1!=lab[i1].c1 ||
        ref[i2].c2!=lab[i1].c2)
      continue;
    n1=lab[i1].adr;
    if (SetRef1(mem,i2,n1)) return (-1);
  }
  return (0);
}

N4 SetRef(N1 *mem,N4 i1)
{ N4 i2,n1;
  for (i2=0;i2<LABNUM && lab[i2].adr;++i2)
  { if (lab[i2].c1!=ref[i1].c1 ||
        lab[i2].c2!=ref[i1].c2)
      continue;
    n1=lab[i2].adr;
    if (SetRef1(mem,i1,n1)) return (-1);
    break;
  }
  return (0);
}

N4 SetRef1(N1 *mem,N4 i1,N4 n1)
{ N4 j1,j2; N1 *p1,cc;
  p1=mp1(mem,ref[i1].adr);
  if (ref[i1].typ==1)
  { for (j2=28,j1=0;j1<8;++j1)
    { cc=(n1>>j2)&0xF; j2-=4;
      if (cc<10) cc+='0';
      else cc+='A'-10;
      *p1++=cc;
    }
  } else
  { n1-=ref[i1].adr;
    if (Typ(I4,n1)>Typ(I4,0x00007FFFul) ||
        Typ(I4,n1)<Typ(I4,0xFFFF8000ul))
      ERR3("Error: (%lu,%lu): Ref: Len: %08lX",
      ref[i1].y,ref[i1].x,n1);
    for (j2=12,j1=0;j1<4;++j1)
    { cc=(n1>>j2)&0xF; j2-=4;
      if (cc<10) cc+='0';
      else cc+='A'-10;
      *p1++=cc;
    }
  }
  ref[i1].adr=0;
  return (0);
}

N1 *Num2Str(N1 sn,N1 bs,N4 num,N1 *s1,N1 l1)
{ if (!s1) return (NULL);
  s1+=9; *s1--=0;
  if (sn)
  { if (num&Bit(31))
    { num=-num; }
    else sn=0;
  }
  if (!num && !l1) *s1--='0';
  else while (num || l1)
  { if (l1) --l1;
    switch (bs)
    { case 10:
        *s1=num%10+'0';
        --s1; num/=10;
        break;
      case 16:
        *s1=num&0xF;
        *s1+=((*s1<10)?'0':'A'-10);
        --s1; num>>=4;
        break;
      default: return (NULL);
    }
  }
  if (sn) *s1--='-';
  return (s1+1);
}

N4 StrH2Num(N1 *buf)
{ N4 num=0; N1 c1;

  if (!buf) return (0);
  for (;*buf;++buf)
  { if ('0'<=*buf && *buf<='9')
      c1=*buf-'0'; else
      c1=*buf-'A'+10;
    num=(num<<4)|c1;
  }

  return (num);
}

N4 StrD2Num(N1 *buf)
{ N4 num=0;

  if (!buf) return (0);
  for (;*buf;++buf)
    num=(num*10)+(*buf-'0');

  return (num);
}

N4 Str2Num(N1 *buf)
{ N4 n1; N1 sn=0;
  if (!buf || !*buf) return (0);
  if (*buf=='+') ++buf; else
  if (*buf=='-') { sn=1; ++buf; }
  if (*buf=='x') n1=StrH2Num(buf+1);
  else n1=StrD2Num(buf);
  if (sn) n1=-n1;
  return (n1);
}

//============= Debug ================================================

xx putc1(N1 c1)
{ fputc(c1,stdout);
}
xx puts1(Str s1)
{ fputs(s1,stdout);
}
int getc1(xx)
{ return (fgetc(stdin));
}
xx gets0(int *ii,N1 *cc)
{ while (*ii!=-1 && *cc!='\n')
  { *ii=getc1(); *cc=(N1)*ii; }
}
N4 gets1(N1 *s1,N4 l1,N1 c1,int *ii,N1 *cc)
{ N4 i1; for (i1=0;i1<l1;++i1)
  { *ii=getc1(); *cc=0;
    if (*ii==-1) break;
    else *cc=(N1)*ii;
    if (*cc=='\n') break;
    if (*cc==c1) break;
    if (*cc=='\r')
    { --i1; continue; }
    s1[i1]=*cc;
  }
  s1[i1]=0; return (i1);
}

N4 deb(N1 *mem,N4 *tip)
{ N1 buf[16],cc=0; int ii=0;
  N1 *pip,*p1; N4 *psp,ml,i1,i2;

  ml=gREG(rMAX);
  if (*tip && mn4x(mem,rIP)==*tip) *tip=0;

  if (!*tip) {
  puts1("FL (");
  puts1(Num2Str(0,16,gREG(rFL),buf,8));
  puts1(")  ");
  puts1("IP (");
  puts1(Num2Str(0,16,gREG(rIP),buf,8));
  puts1(")  ");
  puts1("SP (");
  puts1(Num2Str(0,16,gREG(rSP),buf,8));
  puts1(")  ");
  puts1("BP (");
  puts1(Num2Str(0,16,gREG(rBP),buf,8));
  puts1(")  ");
  puts1("\n");
  puts1("D1 (");
  puts1(Num2Str(0,16,gREG(rD1),buf,8));
  puts1(")  ");
  puts1("D2 (");
  puts1(Num2Str(0,16,gREG(rD2),buf,8));
  puts1(")  ");
  puts1("CNT(");
  puts1(Num2Str(0,16,gREG(rCNT),buf,8));
  puts1(")  ");
  puts1("TIM(");
  puts1(Num2Str(0,16,gREG(rTIM),buf,8));
  puts1(")  ");
  puts1("\n");
  puts1("MAX(");
  puts1(Num2Str(0,16,gREG(rMAX),buf,8));
  puts1(")  ");
  puts1("LEN(");
  puts1(Num2Str(0,16,gREG(rLEN),buf,8));
  puts1(")  ");
  puts1("BEG(");
  puts1(Num2Str(0,16,gREG(rBEG),buf,8));
  puts1(")  ");
  puts1("BLK(");
  puts1(Num2Str(0,16,gREG(rBLK),buf,8));
  puts1(")  ");
  puts1("\n");

  pip=gIP; psp=gSP;
  if (mMem(mem,pip,1))
    ERR0("Error: Debug: IP");
  puts1("CMD: '");
  putc1(*pip); puts1("'");
  puts1(Num2Str(0,16,*pip,buf,2));
  if (!mMem(mem,psp,1))
  { puts1("  ("); i1=mx4(psp[0]);
    puts1(Num2Str(0,16,i1,buf,8));
    puts1(")");
  }
  if (!mMem(mem,psp,2))
  { puts1("  ("); i1=mx4(psp[1]);
    puts1(Num2Str(0,16,i1,buf,8));
    puts1(")");
  }
  if (!mMem(mem,psp,3))
  { puts1("  ("); i1=mx4(psp[2]);
    puts1(Num2Str(0,16,i1,buf,8));
    puts1(")");
  }
  if (!mMem(mem,psp,4))
  { puts1("  ("); i1=mx4(psp[3]);
    puts1(Num2Str(0,16,i1,buf,8));
    puts1(")");
  }
  puts1("\n"); }

  if (!*tip) do
  { ii=getc1();
    if (ii==-1) break;
    else cc=(N1)ii;
    switch (cc)
    { case '?':
      case 'h':
        puts1("Commands:\n");
        puts1("  ?: This help\n");
        puts1("  h: This help\n");
        puts1("  q: Exit\n");
        puts1("  r: Registers\n");
        puts1("  t: Trace\n");
        puts1("  p<hexadr#8>: Proceed till\n");
        puts1("  g<hexadr#8>: Get d1 at\n");
        puts1("  G<hexadr#8>: Get d4 at\n");
        puts1("  s<hexadr#8>,<hexdat#2>: Set d1 at\n");
        puts1("  S<hexadr#8>,<hexdat#8>: Set d4 at\n");
        gets0(&ii,&cc);
        break;
      case 'q':
        gets0(&ii,&cc);
        ii=-1; break;
      case 'r':
        gets0(&ii,&cc);
        break;
      case '\n':
      case 't':
        gets0(&ii,&cc);
        cc=0; break;
      case 'p': BEG;
        i1=gets1(buf,8,'\n',&ii,&cc);
        if (i1<1) break;
        i1=StrH2Num(buf);
        p1=mp1(mem,i1);
        if (!mMem(mem,p1,1)) *tip=i1;
        END; gets0(&ii,&cc);
        if (*tip) cc=0;
        break;
      case 'g': BEG;
        i1=gets1(buf,8,'\n',&ii,&cc);
        if (i1<1) break;
        i1=StrH2Num(buf);
        p1=mp1(mem,i1);
        if (!mMem(mem,p1,1))
        { i1=mn1(p1,0);
          puts1("DAT: ");
          puts1(Num2Str(0,16,i1,buf,2));
          puts1("\n");
        }
        END; gets0(&ii,&cc);
        break;
      case 'G': BEG;
        i1=gets1(buf,8,'\n',&ii,&cc);
        if (i1<1) break;
        i1=StrH2Num(buf);
        p1=mp1(mem,i1);
        if (!mMem(mem,p1,4))
        { i1=mn4x(p1,0);
          puts1("DAT: ");
          puts1(Num2Str(0,16,i1,buf,8));
          puts1("\n");
        }
        END; gets0(&ii,&cc);
        break;
      case 's': BEG;
        i1=gets1(buf,8,',',&ii,&cc);
        if (i1<1) break;
        i1=StrH2Num(buf);
        if (cc!=',') break;
        i2=gets1(buf,2,'\n',&ii,&cc);
        if (i2<1) break;
        i2=(N1)StrH2Num(buf+1);
        p1=mp1(mem,i1);
        if (!mMem(mem,p1,1))
        { mn1(p1,0)=(N1)i2;
          puts1("DAT: ");
          puts1(Num2Str(0,16,i2,buf,2));
          puts1("\n");
        }
        END; gets0(&ii,&cc);
        break;
      case 'S': BEG;
        i1=gets1(buf,8,',',&ii,&cc);
        if (i1<1) break;
        i1=StrH2Num(buf);
        if (cc!=',') break;
        i2=gets1(buf,8,'\n',&ii,&cc);
        if (i2<1) break;
        i2=(N4)StrH2Num(buf+1);
        p1=mp1(mem,i1);
        if (!mMem(mem,p1,4))
        { mn4(p1,0)=mx4(i2);
          puts1("DAT: ");
          puts1(Num2Str(0,16,i2,buf,8));
          puts1("\n");
        }
        END; gets0(&ii,&cc);
        break;
    }
    if (cc==0) break;
  } while (ii!=-1 && cc!='\n');
  if (ii==-1) return (-1);

  return ((cc=='\n') ? 1 : 0);
}

//============= File =================================================

// ret: -1 - Error
// ret:  0 - File
// ret:  1 - Directory
N4 FileCheck(Str nam,N4 *len,N4 *tms)
{ struct stat st; N4 ret=0;

  if (!nam) return (-1);
  if (stat((char *)nam,&st)==-1) return (-1);
  if (S_ISDIR(st.st_mode)) ret=1;
  if (len) *len=st.st_size;
  if (tms)
  { if (ret) *tms=st.st_ctime;
    else *tms=st.st_mtime;
  }

  return (ret);
}

N4 FileCreate(Str nam)
{ int id; N4 i1;

  i1=StrLen(nam);
  if (!nam || !i1) return (0);
  if (nam[i1-1]=='/')
  { nam[i1-1]=0;
#if defined(___OS_WIN)
    if (mkdir((char *)nam)==-1) return (-1);
#else
    if (mkdir((char *)nam,0644)==-1) return (-1);
#endif
  } else
  { if ((id=creat((char *)nam,0644))==-1) return (-1);
    close(id);
  }

  return (0);
}

N4 FileDelete(Str nam)
{ N4 i1;

  i1=StrLen(nam);
  if (!nam || !i1) return (0);
  if (nam[i1-1]=='/')
  { nam[i1-1]=0;
    if (rmdir((char *)nam)==-1) return (-1);
  } else
  { if (unlink((char *)nam)==-1) return (-1);
  }

  return (0);
}

N4 FileOpen(N1 mod,Str nam)
{ int id,mod2;

  switch (mod)
  { case FileOpenRead :
      mod2=O_RDONLY;
      break;
    case FileOpenWrite :
      mod2=O_WRONLY;
      break;
    case (FileOpenRead|FileOpenWrite) :
      mod2=O_RDWR;
      break;
    default :
      return (-1);
  }
#if defined(___OS_WIN)
  mod2|=O_BINARY;
#endif
  if ((id=open((char *)nam,mod2))==-1) return (-1);

  return ((N4)(I4)id);
}

xx FileClose(N4 id)
{ if (id!=-1) close((int)id);
}

N4 FileRead(N4 id,Ptr buf,N4 len)
{ if (!buf && len) return (-1);
  return ((N4)(I4)read((I4)id,buf,len));
}

N4 FileWrite(N4 id,Ptr buf,N4 len)
{ if (!buf && len) return (-1);
  return ((N4)(I4)write((I4)id,buf,len));
}

N4 FileSeek(N1 mod,N4 id,I4 pos)
{ int mod2;

  switch (mod)
  { case FileSeekBeg :
      mod2=SEEK_SET;
      break;
    case FileSeekEnd :
      mod2=SEEK_END;
      break;
    case FileSeekCur :
      mod2=SEEK_CUR;
      break;
    default :
      return (-1);
  }
  return ((N4)(I4)lseek((int)id,pos,mod2));
}

N4 FileResize(N4 id,N4 len)
{
#if defined(___OS_WIN)
  if (chsize((int)id,len)==-1)
#else
  if (ftruncate((int)id,len)==-1)
#endif
    return (-1); else return (0);
}

N4 FileRename(Str nam1,Str nam2)
{ if (rename((char *)nam1,(char *)nam2)==-1)
    return (-1); else return (0);
}

//====================================================================

#include "lib/sys.c"
MAIN
